package com.ruoyi.system.sms;

import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 短信验证码服务
 *
 * @author ruoyi
 */
@Slf4j
@Service
public class SmsCodeService {

    @Autowired
    private AliyunSmsService aliyunSmsService;

    @Autowired
    private RedisCache redisCache;

    @Value("${aliyun.sms.enabled:false}")
    private boolean smsEnabled;

    @Value("${aliyun.sms.mock.enabled:false}")
    private boolean mockEnabled;

    // Redis键前缀
    private static final String SMS_CODE_PREFIX = "sms_code:";
    private static final String SMS_SEND_LIMIT_PREFIX = "sms_send_limit:";

    // 验证码有效期（分钟）
    private static final int CODE_EXPIRE_MINUTES = 5;

    // 发送频率限制（秒）
    private static final int SEND_LIMIT_SECONDS = 60;

    // 模拟验证码固定值
    private static final String MOCK_SMS_CODE = "1234";

    /**
     * 发送短信验证码
     *
     * @param phoneNumber 手机号
     * @param scene 场景（register-注册，login-登录）
     * @return 是否发送成功
     */
    public boolean sendSmsCode(String phoneNumber, String scene) {
        if (!smsEnabled && !mockEnabled) {
            log.warn("短信验证码功能已禁用，跳过发送短信验证码");
            throw new ServiceException("短信验证码功能暂未开放，请联系管理员");
        }

        // 1. 验证手机号格式
        if (!aliyunSmsService.isValidPhoneNumber(phoneNumber)) {
            throw new ServiceException("手机号格式不正确");
        }

        String limitKey = SMS_SEND_LIMIT_PREFIX + phoneNumber;
        // 2. 检查发送频率限制
        if (!mockEnabled) {
            if (redisCache.hasKey(limitKey)) {
                throw new ServiceException("发送过于频繁，请稍后再试");
            }
        }

        String code;
        boolean sendResult;

        if (mockEnabled) {
            // 模拟模式：使用固定验证码1234
            code = MOCK_SMS_CODE;
            sendResult = true;
            log.info("模拟模式：短信验证码发送成功，手机号：{}，场景：{}，验证码：{}", phoneNumber, scene, code);
        } else {
            // 正常模式：生成随机验证码并发送短信
            code = aliyunSmsService.generateSmsCode();
            sendResult = aliyunSmsService.sendSmsCode(phoneNumber, code);
            if (!sendResult) {
                throw new ServiceException("短信发送失败，请稍后重试");
            }
            log.info("短信验证码发送成功，手机号：{}，场景：{}", phoneNumber, scene);
        }

        // 3. 存储验证码到Redis
        String codeKey = SMS_CODE_PREFIX + scene + ":" + phoneNumber;
        redisCache.setCacheObject(codeKey, code, CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);

        // 4. 设置发送频率限制
        redisCache.setCacheObject(limitKey, "1", SEND_LIMIT_SECONDS, TimeUnit.SECONDS);

        return true;
    }

    /**
     * 验证短信验证码
     *
     * @param phoneNumber 手机号
     * @param code 验证码
     * @param scene 场景（register-注册，login-登录）
     * @return 是否验证成功
     */
    public boolean verifySmsCode(String phoneNumber, String code, String scene) {
        if (!smsEnabled & !mockEnabled) {
            log.warn("短信验证码功能已禁用，验证失败");
            return false;
        }

        if (StringUtils.isEmpty(phoneNumber) || StringUtils.isEmpty(code)) {
            return false;
        }

        // 模拟模式：直接验证固定验证码1234
        if (mockEnabled) {
            boolean isValid = MOCK_SMS_CODE.equals(code);
            if (isValid) {
                log.info("模拟模式：短信验证码验证成功，手机号：{}，场景：{}，验证码：{}", phoneNumber, scene, code);
            } else {
                log.warn("模拟模式：短信验证码验证失败，手机号：{}，场景：{}，输入验证码：{}", phoneNumber, scene, code);
            }
            return isValid;
        }

        // 正常模式：从Redis获取验证码进行验证
        String codeKey = SMS_CODE_PREFIX + scene + ":" + phoneNumber;
        String cachedCode = redisCache.getCacheObject(codeKey);

        if (StringUtils.isEmpty(cachedCode)) {
            return false;
        }

        boolean isValid = code.equals(cachedCode);
        if (isValid) {
            // 验证成功后删除验证码
            redisCache.deleteObject(codeKey);
        }

        return isValid;
    }

    /**
     * 检查验证码是否存在（不删除）
     *
     * @param phoneNumber 手机号
     * @param scene 场景
     * @return 是否存在
     */
    public boolean hasSmsCode(String phoneNumber, String scene) {
        String codeKey = SMS_CODE_PREFIX + scene + ":" + phoneNumber;
        return redisCache.hasKey(codeKey);
    }

    /**
     * 删除验证码
     *
     * @param phoneNumber 手机号
     * @param scene 场景
     */
    public void deleteSmsCode(String phoneNumber, String scene) {
        String codeKey = SMS_CODE_PREFIX + scene + ":" + phoneNumber;
        redisCache.deleteObject(codeKey);
    }
}
